﻿using Model;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tool
{
    /// <summary>
    /// 获取JOP参数
    /// </summary>
    /// <param name="vel">速度</param>
    /// <param name="acc">加速度</param>
    /// <param name="dec">减速度</param>
    public delegate void ChangeJopParams(ref double vel, ref double acc, ref double dec);

    /// <summary>
    /// 获取P2P运动参数
    /// </summary>
    /// <param name="vel">速度</param>
    /// <param name="acc">加速度</param>
    /// <param name="dec">减速度</param>
    /// <param name="smoothTime">平滑时间</param>
    public delegate void DelP2pParams(ref double vel, ref double acc, ref double dec, ref short smoothTime);

    public class GuGao
    {

        /// <summary>
        /// 时钟值，使用默认值即可
        /// </summary>
        uint clk;

        /// <summary>
        /// 规划位置
        /// </summary>
        double prfpos;

        /// <summary>
        /// 更新X轴位置
        /// </summary>
        public Action<double> UpdateX;

        /// <summary>
        /// 更新Y轴位置
        /// </summary>
        public Action<double> UpdateY;

        /// <summary>
        /// 更新Z轴位置
        /// </summary>
        public Action<double> UpdateZ;

        /// <summary>
        /// 更新正限位状态
        /// </summary>
        public Action<int> UpdatePositiveLimit;
        /// <summary>
        /// 更新负限位状态
        /// </summary>
        public Action<int> UpdateNegativeLimit;

        /// <summary>
        /// 获取界面JOP参数
        /// </summary>
        public ChangeJopParams changeJopParams;

        /// <summary>
        /// 获取界面P2P设置参数
        /// </summary>
        public DelP2pParams delP2PParams;

        /// <summary>
        /// 设置JOP运动参数
        /// </summary>
        gts.mc.TJogPrm jog;

        /// <summary>
        /// 速度
        /// </summary>
        double vel;

        /// <summary>
        /// P2P运动参数
        /// </summary>
        gts.mc.TTrapPrm trap;

        /// <summary>
        /// JOP重置功能
        /// </summary>
        public void Jop_Reset()
        {
            //复位
            gts.mc.GT_Reset();
            gts.mc.GT_LoadConfig("GT800_test.cfg");//下载配置文件
            gts.mc.GT_ClrSts(1, 4);//清除各轴报警和限位
            gts.mc.GT_PrfJog(1);//设置为jog模式
            gts.mc.GT_PrfJog(2);//设置为jog模式
            gts.mc.GT_PrfJog(4);//设置为jog模式
            gts.mc.GT_ZeroPos(1, 8);//位置清零
        }

        /// <summary>
        /// P2P重置
        /// </summary>
        public void P2P_Reset()
        {
            gts.mc.GT_Reset();
            gts.mc.GT_LoadConfig("GT800_test.cfg");//下载配置文件
            gts.mc.GT_ClrSts(1, 8);//清除各轴报警和限位
            gts.mc.GT_ZeroPos(1, 8);
        }

        public void TimeTick(object sender, EventArgs e)
        {
            //读取1轴的规划位置并显式在界面上
            gts.mc.GT_GetPrfPos(1, out prfpos, 1, out clk);
            UpdateX(prfpos);

            //读取2轴的规划位置并显式在界面上
            gts.mc.GT_GetPrfPos(2, out prfpos, 1, out clk);
            UpdateY(prfpos);

            //读取4轴的规划位置并显式在界面上
            gts.mc.GT_GetPrfPos(4, out prfpos, 1, out clk);
            UpdateZ(prfpos);

            //结果
            int lGpiValue;

            //读取正限位状态
            gts.mc.GT_GetDi(3, out lGpiValue);
            UpdatePositiveLimit(lGpiValue);

            //读取负限位状态
            gts.mc.GT_GetDi(1, out lGpiValue);
            UpdateNegativeLimit(lGpiValue);


        }

        /// <summary>
        /// 打开板卡
        /// </summary>
        /// <param name="index"></param>
        public void GuGaoOpen(int index)
        {
            gts.mc.GT_Open(0, (short)index);//打开运动控制板卡
        }


        /// <summary>
        /// JOP 按下移动
        /// </summary>
        /// <param name="index">轴号</param>
        /// <param name="movement">移动方向:前/后/左/右/升/降</param>
        public void Jop_Move(int index, MovementDirection movement)
        {
            //获取界面JOP参数
            changeJopParams(ref vel, ref jog.acc, ref jog.dec);
            //获取是正或负，不同方向的JOP运动
            int value = movement == MovementDirection.left || movement == MovementDirection.front || movement == MovementDirection.rise ? 1 : -1;

            //设置JOP参数
            gts.mc.GT_SetJogPrm((short)index, ref jog);//设置jog运动参数
            gts.mc.GT_SetVel((short)index, vel * value);//设置目标速度
            gts.mc.GT_Update(1 << ((short)index - 1));//更新轴运动

        }
        /// <summary>
        /// JOP 停止
        /// </summary>
        /// <param name="index"></param>
        public void Jop_Stop(int index)
        {
            gts.mc.GT_Stop(1 << ((short)index - 1), 0);
        }

        /// <summary>
        /// P2P移动
        /// </summary>
        /// <param name="axis">轴号</param>
        /// <param name="pos">移动的脉冲量</param>
        public void P2P_Move(int axis, int pos)
        {
            //调用委托获取界面参数
            delP2PParams(ref vel, ref trap.acc, ref trap.dec, ref trap.smoothTime);

            gts.mc.GT_SetTrapPrm((short)axis, ref trap);//设置点位运动参数
            gts.mc.GT_SetVel((short)axis, vel);//设置目标速度
            gts.mc.GT_SetPos((short)axis, pos);//设置目标位置
            gts.mc.GT_Update(1 << (axis - 1));//更新轴运动
        }

        /// <summary>
        /// 停止指定轴的P2P运动
        /// </summary>
        /// <param name="axis"></param>
        public void P2P_Stop(int axis)
        {
            gts.mc.GT_Stop(1 << (axis - 1), 0);
        }

        /// <summary>
        /// 建立X、Y直线插补的坐标系
        /// </summary>
        public void Establish_coordinate_system()
        {
            short sRtn;
            gts.mc.TCrdPrm crdPrm = new gts.mc.TCrdPrm();

            crdPrm.dimension = 3;                        // 建立三维的坐标系
            crdPrm.synVelMax = 500;                      // 坐标系的最大合成速度是: 500 pulse/ms
            crdPrm.synAccMax = 2;                        // 坐标系的最大合成加速度是: 2 pulse/ms^2
            crdPrm.evenTime = 0;                         // 坐标系的最小匀速时间为0
            crdPrm.profile1 = 1;                       // 规划器1对应到X轴                       
            crdPrm.profile2 = 2;                       // 规划器2对应到Y轴
            crdPrm.profile3 = 3;                       // 规划器3对应到Z轴
            crdPrm.profile4 = 0;
            crdPrm.profile5 = 0;
            crdPrm.profile6 = 0;
            crdPrm.profile7 = 0;
            crdPrm.profile8 = 0;

            crdPrm.setOriginFlag = 1;                    // 需要设置加工坐标系原点位置
            crdPrm.originPos1 = 0;                     // 加工坐标系原点位置在(0,0,0)，即与机床坐标系原点重合
            crdPrm.originPos2 = 0;
            crdPrm.originPos3 = 0;
            crdPrm.originPos4 = 0;
            crdPrm.originPos5 = 0;
            crdPrm.originPos6 = 0;
            crdPrm.originPos7 = 0;
            crdPrm.originPos8 = 0;

            sRtn = gts.mc.GT_SetCrdPrm(1, ref crdPrm); // 建立坐标系编号:1
        }

        public void Linear_Difference_Compensation_Move(List<Point> points)
        {
            short sRtn;// 指令返回值变量

            // 即将把数据存入坐标系1的FIFO0中，所以要首先清除此缓存区中的数据
            sRtn = gts.mc.GT_CrdClear(1, 0);

            foreach (Point item in points)
            {
                // 向缓存区写入插补数据
                sRtn = gts.mc.GT_LnXY(
                    1,				// 该插补段的坐标系是坐标系1
                    item.X, item.Y,		// 该插补段的终点坐标(200000, 0)
                    100,				// 该插补段的目标速度：100pulse/ms
                    0.1,				// 插补段的加速度：0.1pulse/ms^2
                    0,				// 终点速度为0
                    0);             // 向坐标系1的FIFO0缓存区传递该直线插补数据
            }


            // 缓存区数字量输出
            sRtn = gts.mc.GT_BufIO(
                1,				// 坐标系是坐标系1
                (ushort)gts.mc.MC_GPO,		// 数字量输出类型：通用输出
                0xffff,			// bit0~bit15全部都输出
                0x55,			// 输出的数值为0x55
                0);             // 向坐标系1的FIFO0缓存区传递该数字量输出


            // 缓存区延时指令
            sRtn = gts.mc.GT_BufDelay(
                1,				// 坐标系是坐标系1
                400,				// 延时400ms
                0);				// 向坐标系1的FIFO0缓存区传递该延时

            // 启动坐标系1的FIFO0的插补运动
            sRtn = gts.mc.GT_CrdStart(1, 0);
        }


        public void LeftArcInterpolationTest()
        {
            Establish_coordinate_system();

            short sRtn;

            // 清除坐标系1的FIFO0中的数据
            sRtn = gts.mc.GT_CrdClear(1, 0);

            // 设置起始点，假设起始点在(0, 0)
            sRtn = gts.mc.GT_LnXY(1, 0, 0, 1, 0.1, 0, 0);

            // 向缓存区写入圆弧插补数据，以圆心描述方法描述了一个左圆弧
            sRtn = gts.mc.GT_ArcXYC(
                1,                  // 坐标系是坐标系1
                -10000, 0,          // 该圆弧的终点坐标(-10000, 0)
                -5000, 5000,        // 圆弧插补的圆心相对于起点位置的偏移量(-5000, 5000)
                1,                  // 该圆弧是逆时针圆弧
                1,                  // 该插补段的目标速度：100pulse/ms
                0.1,                // 该插补段的加速度：0.1pulse/ms^2
                0,                  // 终点速度为0
                0);                 // 向坐标系1的FIFO0缓存区传递该圆弧插补数据

            // 启动插补运动
            sRtn = gts.mc.GT_CrdStart(1, 0);

            if (sRtn != 0)
            {
                Console.WriteLine("圆弧插补测试失败，错误代码: " + sRtn);
            }
            else
            {
                Console.WriteLine("圆弧插补测试成功");
            }
        }


        public void ArcInterpolationTest(int startX, int startY, int endX, int endY, int centerX, int centerY, bool isClockwise, int targetVelocity, double acceleration)
        {
            Establish_coordinate_system();//建立坐标系

            short sRtn;

            // 清除坐标系1的FIFO0中的数据
            sRtn = gts.mc.GT_CrdClear(1, 0);

            // 设置起始点
            sRtn = gts.mc.GT_LnXY(1, startX, startY, targetVelocity, acceleration, 0, 0);

            // 计算圆心相对于起点位置的偏移量
            int offsetX = centerX - startX;
            int offsetY = centerY - startY;

            // 设置方向：1表示逆时针，0表示顺时针
            int direction = isClockwise ? 0 : 1;

            // 向缓存区写入圆弧插补数据
            sRtn = gts.mc.GT_ArcXYC(
                1,                  // 坐标系是坐标系1
                endX, endY,         // 该圆弧的终点坐标
                offsetX, offsetY,   // 圆弧插补的圆心相对于起点位置的偏移量
                (short)direction,          // 圆弧方向
                targetVelocity,     // 该插补段的目标速度
                acceleration,       // 该插补段的加速度
                0,                  // 终点速度为0
                0);                 // 向坐标系1的FIFO0缓存区传递该圆弧插补数据

            // 启动插补运动
            sRtn = gts.mc.GT_CrdStart(1, 0);

            if (sRtn != 0)
            {
                Console.WriteLine("圆弧插补测试失败，错误代码: " + sRtn);
            }
            else
            {
                Console.WriteLine("圆弧插补测试成功");
            }
        }


    }
}
